package com.wd.tw.websocket.client;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wd.tw.domain.dto.request.SubscribeRequest;
import com.wd.tw.domain.dto.response.SocketEventResponse;
import com.wd.tw.service.EventService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.NotYetConnectedException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 自定义WebSocket客户端
 *
 * @author machenike
 */
@Slf4j
@Setter
public class CustomizedWebSocketClient extends WebSocketClient {


    private EventService eventService;


    /**
     * 消息回调接口
     */
    private WebSocketClientSyncCallback callback = null;

    private WebSocketClientSyncCallback callbackListen = null;


    /**
     * 线程安全的Boolean -是否受到消息
     */
//    public AtomicBoolean hasMessage = new AtomicBoolean(false);

    /**
     * 线程安全的Boolean -是否已经连接
     */
    private AtomicBoolean hasConnection = new AtomicBoolean(false);

    private ConcurrentHashMap<String, Boolean> sidMap = new ConcurrentHashMap<>();

    private String boxId;

    /**
     * 构造方法
     *
     * @param serverUri
     */
    public CustomizedWebSocketClient(URI serverUri) {
        super(serverUri);
        log.info("CustomizeWebSocketClient init:" + serverUri.toString());
    }

    /**
     * 构造方法
     *
     * @param serverUri
     */
    public CustomizedWebSocketClient(URI serverUri, EventService eventService,String boxId) {
        super(serverUri);
        this.eventService = eventService;
        this.boxId=boxId;
        log.info("CustomizeWebSocketClient init:" + serverUri.toString());
    }

    /**
     * 打开连接时
     *
     * @param serverHandshake
     */
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        log.info("CustomizeWebSocketClient onOpen");
        sidMap = new ConcurrentHashMap<>();
        hasConnection.set(true);

        String param = new SubscribeRequest().toString();
        log.info("send to socket:" + param);
        send(param);


    }

    /**
     * 收到消息时
     *
     * @param s
     */
    @Override
    public void onMessage(String s) {
        log.info("receive strMessage from socket:" + s);
    }

    @Override
    public void onMessage(ByteBuffer byteBuffer) {
        log.info("receive byteMessage from socket!");

        StringBuilder hexString = new StringBuilder();

        while (byteBuffer.hasRemaining()) {
            hexString.append(String.format("%02X", byteBuffer.get())); // 获取每个字节并格式化为 2 位十六进制
        }
        String rawString = hexString.toString();


        byte[] dd = HexUtil.decodeHex(rawString.substring(8, 16));
        int length = Convert.bytesToInt(dd);
        log.info("jsonLength:" + length);

        String str = HexUtil.decodeHexStr(rawString).substring(8, length + 8);

        log.info("jsonStr2:" + str.substring(0, str.lastIndexOf("}}") + 2));


        String jsonStr = str.substring(0, str.lastIndexOf("}}") + 2);


        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        try {
            SocketEventResponse response = objectMapper.readValue(jsonStr, SocketEventResponse.class);
            List<SocketEventResponse.DataWrapper.EventDetect.DetectListItem> detect_list = response.getData().getEvent_detect().getDetect_list();
            needToAlarm(detect_list);
            int channel_id = response.getData().getEvent_detect().getChannel_id();
            log.info("edge box channel id:" + channel_id);
            eventService.edgeBoxEvent(channel_id,boxId);
        } catch (IOException e) {
            e.printStackTrace();
            log.info("trans error:", e);
        }

    }

    public boolean needToAlarm(List<SocketEventResponse.DataWrapper.EventDetect.DetectListItem> detect_list) {
        log.info("detect_list", JSONObject.toJSONString(detect_list));
        for (int i = 0; i < detect_list.size(); i++) {
            String event_type = detect_list.get(i).getEvent_info().getEvent_type();
            log.info("event_type:" + event_type);
        }
        return true;
    }

    public static void main(String[] args) {
        String a = "{\"basic\":{\"ver\":\"1.0\",\"code\":200,\"msg\":\"success\",\"time\":1732167886},\"data\":{\"event_detect\":{\"channel_id\":5,\"channel_name\":\"二醫1樓梯廳\",\"detect_time\":1732167886237000,\"scene_pic\":\"0,147840\",\"detect_list\":[{\"detect_pic\":\"147840,18848\",\"event_info\":{\"event_type\":\"bed\",\"target_info\":{\"target_type\":\"bed\",\"target_id\":947913553,\"quality_score\":0,\"target_rect\":{\"x\":949,\"y\":205,\"width\":209,\"height\":225},\"attribute\":{\"custom_common_attribute\":[]}},\"event_status\":\"event_trigger\",\"event_rule\":{\"region_event_detect\":[{\"id\":0,\"region_coordinate\":{\"point\":[{\"x\":173,\"y\":106},{\"x\":1627,\"y\":106},{\"x\":1627,\"y\":985},{\"x\":173,\"y\":985}]}}]}}}]}}}";
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        try {
            SocketEventResponse response = objectMapper.readValue(a, SocketEventResponse.class);
            List<SocketEventResponse.DataWrapper.EventDetect.DetectListItem> detect_list = response.getData().getEvent_detect().getDetect_list();
            System.out.println(JSONObject.toJSONString(response));
            int channel_id = response.getData().getEvent_detect().getChannel_id();
            log.info("edge box channel id:" + channel_id);

        } catch (IOException e) {
            e.printStackTrace();
            log.info("trans error:", e);
        }
    }

    // 十六进制字符串转换为字节数组
    public byte[] hexStringToByteArray(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }


    /**
     * 当连接关闭时
     *
     * @param i
     * @param s
     * @param b
     */
    @Override
    public void onClose(int i, String s, boolean b) {
        this.hasConnection.set(false);
        this.sidMap.clear();
        log.info("CustomizeWebSocketClient onClose:{}" + s);
    }

    /**
     * 发生error时
     *
     * @param e
     */
    @Override
    public void onError(Exception e) {
        log.info("CustomizeWebSocketClient onError:", e);
    }


    /**
     * 带有回调的消息发送接口
     *
     * @param text
     * @param callback
     * @throws NotYetConnectedException
     */
    public void send(String sid, String text, WebSocketClientSyncCallback callback) throws NotYetConnectedException {
        log.info("CustomizeWebSocketClient send:{}", text);
        sidMap.put(sid, true);
        //设定回调接口
        this.callback = callback;
        super.send(text);
        //计算等待；10s返回消息 超过10s直接退出
        for (int count = 0; ; ) {
//            log.debug("socketClient wait:"+count+" second, hasMessage："+hasMessage);
            //判断是否收到消息||socket返回数据超时
            if (!sidMap.containsKey(sid) || count > 10) {
                break;
            } else if (count <= 10) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count++;
            }
        }
    }

    @Override
    public void connect() {
        log.info("CustomizeWebSocketClient connect");
        super.connect();
    }


    @Override
    public void reconnect() {
        log.info("CustomizeWebSocketClient reconnect");
        super.reconnect();
    }

    /**
     * 定时判断连接状态:尝试重连 1分钟
     */
//    @Scheduled(cron = "0 0/1 * * * ? ")
    public void autoConnect() {
        log.info("CustomizeWebSocketClient autoConnect: [hasConnection:" + hasConnection + "]");
        if (!hasConnection.get()) {
            this.reconnect();
        }
    }
}

